package system

import (
	"errors"
	"github.com/gookit/color"
	"gorm.io/gorm"
	"seven-admin/app/admin/schemas/query"
	"seven-admin/app/admin/schemas/req"
	"seven-admin/app/collection/system"
	"seven-admin/core/config"
	"seven-admin/core/response"
	"seven-admin/util"
	"strconv"
	"strings"
)

type AuthPermService interface {
	SelectMenuIdsByRoleId(roleId uint, auth *req.AuthReq) (menuIds []uint, e error)
	CacheRoleMenusByRoleId(roleId uint) (e error)
	BatchSaveByMenuIds(roleId uint, menuIds string, db *gorm.DB, auth *req.AuthReq) (e error)
	BatchDeleteByRoleId(roleId uint, db *gorm.DB, auth *req.AuthReq) (e error)
	BatchDeleteByMenuId(menuId uint, auth *req.AuthReq) (e error)
}

type authPermService struct {
	db *gorm.DB
}

// SelectMenuIdsByRoleId 根据角色ID获取菜单ID
func (a authPermService) SelectMenuIdsByRoleId(roleId uint, auth *req.AuthReq) (menuIds []uint, e error) {
	var role system.AuthRole
	if roleId == 0 {
		return []uint{}, nil
	}
	err := a.db.Where("id = ? AND is_disable = ?", roleId, 0).Limit(1).First(&role).Error
	if e = response.CheckErr(err, "SelectMenuIdsByRoleId First err"); e != nil {
		return []uint{}, e
	}
	var perms []system.AuthPerm
	var tenantHasPerms []uint
	err = query.AuthQuery(a.db.Model(&system.AuthTenantPerm{}), auth).Pluck("menu_id", &tenantHasPerms).Error
	if !auth.IsSuperTenant {
		if role.SoftSuperAdmin == 0 {
			if len(tenantHasPerms) > 0 { // 检查tenantHasPerms是否为空
				err = a.db.Where("role_id = ?", role.ID).Find(&perms).Error
				if e = response.CheckErr(err, "SelectMenuIdsByRoleId Find perms err"); e != nil {
					color.Redln("Find perms err: ", err)
					return []uint{}, e
				}
				for _, perm := range perms {
					menuIds = append(menuIds, perm.MenuId)
				}
			}
		} else {
			menuIds = tenantHasPerms
		}
	} else {
		err = a.db.Where("role_id = ?", role.ID).Find(&perms).Error
		if e = response.CheckErr(err, "SelectMenuIdsByRoleId Find err"); e != nil {
			return []uint{}, e
		}
		for _, perm := range perms {
			menuIds = append(menuIds, perm.MenuId)
		}
	}
	return
}

// CacheRoleMenusByRoleId 缓存角色菜单
func (a authPermService) CacheRoleMenusByRoleId(roleId uint) (e error) {
	var role system.AuthRole
	if roleId == 0 {
		return errors.New("roleId is 0")
	}
	superTenantId := config.AdminConfig.SuperTenantId
	err := a.db.Where("id = ? AND is_disable = ?", roleId, 0).Limit(1).First(&role).Error
	if e = response.CheckErr(err, "SelectMenuIdsByRoleId First err"); e != nil {
		return e
	}
	var menus []system.AuthMenu
	var menuIds []uint
	if role.TenantID == superTenantId {
		err := a.db.Model(&system.AuthPerm{}).Where("role_id = ?", roleId).Pluck("menu_id", &menuIds).Error
		if e = response.CheckErr(err, "CacheRoleMenusByRoleId Pluck err"); e != nil {
			return e
		}
	} else {
		var tenantHasPerms []uint
		err = a.db.Model(&system.AuthTenantPerm{}).Where("tenant_id = ?", role.TenantID).Pluck("menu_id", &tenantHasPerms).Error
		if e = response.CheckErr(err, "CacheRoleMenusByRoleId Pluck err"); e != nil {
			return
		}
		if role.SoftSuperAdmin == 1 {
			menuIds = tenantHasPerms
		} else {
			var rolePerms []uint
			err = a.db.Model(&system.AuthPerm{}).Where("role_id = ? AND menu_id in (?)", roleId, tenantHasPerms).Pluck("menu_id", &rolePerms).Error
			if e = response.CheckErr(err, "CacheRoleMenusByRoleId Pluck err"); e != nil {
				return
			}
			menuIds = rolePerms
		}
	}
	err = a.db.Where(
		"is_disable = ? and id in ? and menu_type in ?", 0, menuIds, []string{"C", "A"}).Order(
		"menu_sort asc, id desc").Find(&menus).Error
	if e = response.CheckErr(err, "CacheRoleMenusByRoleId Find menus err"); e != nil {
		return
	}
	var menuArray []string
	if len(config.AdminConfig.CommonUri) > 0 {
		menuArray = append(menuArray, config.AdminConfig.CommonUri...)
	}
	for _, menu := range menus {
		if menu.Perms != "" {
			menuArray = append(menuArray, strings.Trim(menu.Perms, ""))
		}
	}
	util.RedisUtil.HSet(config.AdminConfig.BackstageRolesKey, strconv.FormatUint(uint64(roleId), 10), strings.Join(menuArray, ","), 0)
	return
}

// BatchSaveByMenuIds 批量写入角色菜单
func (a authPermService) BatchSaveByMenuIds(roleId uint, menuIds string, db *gorm.DB, auth *req.AuthReq) (e error) {
	if menuIds == "" {
		return
	}
	if db == nil {
		db = a.db
	}
	err := db.Transaction(func(tx *gorm.DB) error {
		var perms []system.AuthPerm
		for _, menuIdStr := range strings.Split(menuIds, ",") {
			menuId, _ := strconv.ParseUint(menuIdStr, 10, 32)
			perms = append(perms, system.AuthPerm{ID: util.ToolsUtil.MakeUuid(), RoleId: roleId, MenuId: uint(menuId)})
		}
		txErr := tx.Create(&perms).Error
		var te error
		te = response.CheckErr(txErr, "BatchSaveByMenuIds Create in tx err")
		return te
	})
	e = response.CheckErr(err, "BatchSaveByMenuIds Transaction err")
	return
}

// BatchDeleteByRoleId 批量删除角色菜单(根据角色ID)
func (a authPermService) BatchDeleteByRoleId(roleId uint, db *gorm.DB, auth *req.AuthReq) (e error) {
	if db == nil {
		db = a.db
	}
	err := db.Delete(&system.AuthPerm{}, "role_id = ?", roleId).Error
	e = response.CheckErr(err, "BatchDeleteByRoleId Delete err")
	return
}

// BatchDeleteByMenuId 批量删除角色菜单(根据菜单ID)
func (a authPermService) BatchDeleteByMenuId(menuId uint, auth *req.AuthReq) (e error) {
	err := a.db.Delete(&system.AuthPerm{}, "menu_id = ?", menuId).Error
	e = response.CheckErr(err, "BatchDeleteByMenuId Delete err")
	return
}

func NewAuthPermService(db *gorm.DB) AuthPermService {
	return &authPermService{
		db: db,
	}
}
